/*
 * Copyright (c) 2010-2011 Plugger Antonio Begue Ponce. All Rights Reserved.
 *
 * This file is part of Plugger Framework.
 *
 *  Plugger Framework is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version 3 as published by
 *  the Free Software Foundation.
 *
 *  Plugger Framework is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Plugger Framework.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.plugger.ui.viewmodel;

import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.list.ArrayListModel;
import com.jgoodies.binding.list.SelectionInList;
import com.jgoodies.binding.value.ValueModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.ListModel;
import org.plugger.infrastructure.domainbase.EntityBase;
import org.plugger.infrastructure.repositorybase.IWorkspace;
import org.plugger.ui.base.*;

/**
 * An abstract EditableList Controller.
 *
 * @author "Antonio Begue"
 * @version $Revision: 1.0 $
 */
public abstract class EditableListViewModel<T extends EntityBase> extends ViewModelBase {
    private IWorkspace ws;
    private ObjectState currentObjectState;
    private List<T> entitiesList;
    private SelectionInList<T> entitiesView;
    private ArrayListModel<T> managedEntities;
    private T currentEntity;
    private DelegateAction saveAction;
    private DelegateAction newAction;
    private DelegateAction deleteAction;
    private PresentationModel<T> presentationModel;
    private PresentationModel<EditableListViewModel> ownPresentationModel;

    protected EditableListViewModel() {
        this(null);
    }

    protected EditableListViewModel(IView view) {
        super(view);
        ownPresentationModel = new PresentationModel<EditableListViewModel>(this);

        this.currentObjectState = ObjectState.EXISTING;
        this.currentEntity = null; // TODO: default(T);
        this.saveAction = new DelegateAction("Edit", new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                saveCommandHandler(e);
            }
        });
        this.newAction = new DelegateAction("New", new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                newCommandHandler(e);
            }
        });
        this.deleteAction = new DelegateAction("Delete", new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                deleteCommandHandler(e);
            }
        });
    }

    protected final void initialize() {
        populateList();
    }

    protected void populateList() {
        this.entitiesList = this.generateEntitiesList();
        if (this.entitiesView == null) {
            ValueModel selectionHolder = ownPresentationModel.getModel("currentEntity");
            this.entitiesView = new SelectionInList<T>(createManagedEntitiesList(), selectionHolder);
            this.presentationModel = new PresentationModel<T>(this.entitiesView);
        } else {
            this.entitiesView.setListModel(createManagedEntitiesList());
        }
    }

    private ListModel createManagedEntitiesList() {
        managedEntities = new ArrayListModel<T>(this.getEntitiesList());
        return managedEntities;
    }

    protected abstract T buildNewEntity();
    protected abstract List<T> generateEntitiesList();
    protected abstract void saveEntitiesList();
    protected abstract boolean deleteCurrentEntity();
    protected abstract void onCurrentEntitySet(T entity);

    /**
     * @return the currentEntity
     */
    public T getCurrentEntity() {
        return currentEntity;
    }

    /**
     * @param currentEntity the currentEntity to set
     */
    public void setCurrentEntity(T currentEntity) {
        // TODO: Verificar if (this._currentEntity != value)
        this.currentEntity = currentEntity;
//        this.presentationModel.setBean(currentEntity); // = new PresentationModel<T>(currentEntity);
//        this.getEntitiesView().setSelection(currentEntity);
        this.onCurrentEntitySet(currentEntity);
        // TODO: this._saveCommand.IsEnabled = (this._currentEntity != null);
        // TODO: this.OnPropertyChanged(EditableViewModel<T>.currentEntityPropertyName);
//        if (!currentEntity.isNew()) {
//            setCurrentObjectState(ObjectState.EXISTING);
//        }
    }

    /**
     * @return the entitiesView
     */
    public SelectionInList<T> getEntitiesView() {
        return entitiesView;
    }

    /**
     * @return the entitiesList
     */
    public List<T> getEntitiesList() {
        return entitiesList;
    }

    /**
     * @return the managedEntities
     */
    public ArrayListModel<T> getManagedEntities() {
        return managedEntities;
    }

    /**
     * @return the ws
     */
    public IWorkspace getWs() {
        return ws;
    }

    /**
     * @param ws the ws to set
     */
    public void setWs(IWorkspace ws) {
        this.ws = ws;
    }

    /**
     * @return the currentObjectState
     */
    public ObjectState getCurrentObjectState() {
        return currentObjectState;
    }

    /**
     * @param currentObjectState the currentObjectState to set
     */
    public void setCurrentObjectState(ObjectState currentObjectState) {
        this.currentObjectState = currentObjectState;


        // TODO: if (this._currentObjectState != value) {
        //    this._currentObjectState = value;
        //    this.OnPropertyChanged(EditableViewModel<T>.currentObjectStatePropertyName);
        //}
    }

    /**
     * @return the saveAction
     */
    public DelegateAction getSaveAction() {
        return saveAction;
    }

    /**
     * @return the newAction
     */
    public DelegateAction getNewAction() {
        return newAction;
    }

    /**
     * @return the deleteAction
     */
    public DelegateAction getDeleteAction() {
        return deleteAction;
    }

    /**
     * @return the presentationModel
     */
    public PresentationModel<T> getPresentationModel() {
        return presentationModel;
    }

    public void add(T entity) {
        this.entitiesList.add(entity);
        this.managedEntities.add(entity);
    }

    public void remove(T entity) {
        this.entitiesList.remove(entity);
        this.managedEntities.remove(entity);
    }

    public boolean validateEntitiesList() {
        boolean valid = true;
        for (EntityBase entityBase : entitiesList) {
            if (!entityBase.isValidForPersistence()) {
                valid = false;
            }
        }
        return valid;
    }

    public void saveCommandHandler(ActionEvent e) {
        if (this.validateEntitiesList()) {
            this.saveEntitiesList();
            this.setCurrentObjectState(ObjectState.EXISTING);
            this.getEntitiesView().fireSelectedContentsChanged();
        }
    }

    public void newCommandHandler(ActionEvent e) {
        T newEntity = this.buildNewEntity();
        if (newEntity == null) {
            return;
        }
        this.setCurrentObjectState(ObjectState.NEW);
        this.add(newEntity);
        this.getEntitiesView().fireSelectedContentsChanged();
        this.getEntitiesView().setSelection(newEntity);
    }

    public void deleteCommandHandler(ActionEvent e) {
        boolean resp = deleteCurrentEntity();
        if (this.getCurrentEntity() == null || resp == false) {
            return;
        }

        this.remove(this.getCurrentEntity());
        this.setCurrentEntity(null);
        getEntitiesView().fireSelectedContentsChanged();
    }
}
